#include "GraphicsManager.h"
#include "PlatformManager.h"
#include "PScheduler.h"
#include <DXGI.h>

namespace Proton 
{
	namespace Managers
	{

		GraphicsManager::GraphicsManager(GRAPHICS_SETTINGS_DESC *pGsd)
		{
			gsd = *pGsd;
			if (pGsd->msCount < 5) gsd.msCount = pGsd->msCount; else gsd.msCount = 4;

			pPlatform = NULL;
			pScheduler = NULL;

			swapchain = NULL;
			dev = NULL;
			devcon = NULL;
			backbuffer = NULL;
			windowHandle = NULL;
		}


		GraphicsManager::~GraphicsManager(void)
		{
			cleanD3D();
		}

		void GraphicsManager::initialize(PlatformManager* _pPlatform, PScheduler* _pScheduler)
		{
			pPlatform = _pPlatform;
			pScheduler = _pScheduler;

			windowHandle = pPlatform->getWindowHandle();

			// enumerate adapters
			IDXGIAdapter* pAdapter;
			IDXGIFactory* pFactory = NULL;

			CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&pFactory);
			for (UINT i=0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i)
			{
				adapters.push_back(pAdapter);
			}

			if(pFactory)
				pFactory->Release();

			initD3D();
		}


		void GraphicsManager::initD3D()
		{
			HRESULT hr = E_FAIL;
			// DIRECT3D initialization
			DXGI_SWAP_CHAIN_DESC scd;
			ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));

			scd.BufferCount = 1;
			scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
			scd.BufferDesc.Width = gsd.windowWidth;
			scd.BufferDesc.Height = gsd.windowHeight;
			scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
			scd.OutputWindow = windowHandle;
			scd.SampleDesc.Count = gsd.msCount;
			scd.Windowed = !gsd.fullscreen;
			scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

			hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE,
				NULL, NULL, NULL, NULL, D3D11_SDK_VERSION,
				&scd, &swapchain, &dev, &featureLevel, &devcon); 

			// CHECK FEATURE LEVEL; NO DX11 SUPPORT -> QUIT
			if (featureLevel != D3D_FEATURE_LEVEL_11_0)
			{
				pPlatform->messageBox(L"No DirectX 11 support", L"DirectX 11 is required.");
				pScheduler->quit(); //temp, scheduler functionality
				// PlatformManager-ReleaseResources();
				// Scheduler->Quit(ERR);
				return;
			}
			
			// Setting the rendertarget
			
			ID3D11Texture2D *pBackBuffer;
			hr = swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);

			hr = dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
			
			pBackBuffer->Release();

			devcon->OMSetRenderTargets(1, &backbuffer, NULL);
			
			// Setting the viewport
			D3D11_VIEWPORT viewport;
			ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
			viewport.TopLeftX = 0;
			viewport.TopLeftY = 0;
			viewport.Width = (float)gsd.windowWidth;
			viewport.Height = (float)gsd.windowHeight;

			devcon->RSSetViewports(0, &viewport);

			if (FAILED(hr))
			{
				pPlatform->messageBox(L"Whoops", L"Something went wrong");
				pScheduler->quit();
			}
			
		}

		void GraphicsManager::cleanD3D()
		{
			if(swapchain)
			{
				swapchain->SetFullscreenState(false, NULL);
				swapchain->Release();
			}

			if(backbuffer)
				backbuffer->Release();
			if(dev)
				dev->Release();
			if(devcon)
				devcon->Release();
		}
	}
}